/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package syj.singletablemanager;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

/**
 *
 * @author SYJ
 */
public class SingleTableManager
{
    private static final String SPLIT_SIGN = "\t";
    private File phyFile;
    private BasicOperator enforcer;
    private String[] columnNames;
    private boolean autoNumbered;
    private String[] customedCtrlArgs;

    /**
     * 判断某行值是否符合表格缓存
     *
     * @param values 待判断的值
     * @return 判断结果
     */
    private boolean matchedValues(String[] values)
    {
        return values.length == columnNames.length;
    }

    /**
     * 根据{@code enforcer}设置缓存中的{@code columnNames}、{@code autoNumbered}和{@code customedCtrlArgs}
     */
    private void readCtrlLineArgs()
    {
        String[] ctrLineArgs = enforcer.getControlLine().split(SPLIT_SIGN);
        int nColumns = Integer.parseInt(ctrLineArgs[0]);
        columnNames = new String[nColumns];
        for (int i = 0; i < columnNames.length; i++)
        {
            columnNames[i] = ctrLineArgs[i + 1];
        }
        autoNumbered = Boolean.parseBoolean(ctrLineArgs[columnNames.length + 1]);
        customedCtrlArgs = new String[ctrLineArgs.length - 2 - nColumns];
        for (int i = 0; i < customedCtrlArgs.length; i++)
        {
            customedCtrlArgs[i] = ctrLineArgs[2 + nColumns + i];
        }
    }

    /**
     * 根据缓存中的{@code columnNames}、{@code autoNumbered}和{@code customedCtrlArgs}设置{@code enforcer}的{@code ctrLine}
     */
    private void writeCtrlLineArgs()
    {
        String ctrlLine = Integer.toString(this.columnNames.length);
        for (String string : this.columnNames)
        {
            ctrlLine += SPLIT_SIGN + string;
        }
        ctrlLine += SPLIT_SIGN + Boolean.toString(this.autoNumbered);
        if (customedCtrlArgs != null)
        {
            for (String string : this.customedCtrlArgs)
            {
                ctrlLine += SPLIT_SIGN + string;
            }
        }
        enforcer.setControlLine(ctrlLine);
    }

    /**
     * 根据已经存在的表格记录文件创建其缓存
     *
     * @param pathName 表格记录文件的带路径文件名
     * @throws FileNotFoundException {@code pathName}对应的表格记录文件不存在时抛出
     * @throws NumberFormatException 表格记录文件控制行的首个参数不是表格的列数
     */
    public SingleTableManager(String pathName) throws FileNotFoundException,
            NumberFormatException
    {
        phyFile = new File(pathName);
        if (!phyFile.isFile())
        {
            throw new FileNotFoundException("带路径的文件名无效或根据路径名找不到表格对应的真实文件");
        }
        enforcer = new BasicOperator(phyFile, false);
        readCtrlLineArgs();
    }

    /**
     * 根据给定的列名、控制参数创建一个新的表格缓存和对应的真实记录文件，并写入控制行
     *
     * @param pathName 记录文件的带路径文件名
     * @param columnNames 新表的列名
     * @param autoNumbered 新表是否要添加自动编号
     * @param customedCtrlArgs 自定义的控制参数
     * @throws FileNotFoundException
     * @throws IOException
     */
    public SingleTableManager(String pathName, String[] columnNames,
            boolean autoNumbered,
            String[] customedCtrlArgs) throws
            FileNotFoundException, IOException
    {
        phyFile = new File(pathName);
        phyFile.createNewFile();
        enforcer = new BasicOperator(phyFile, true);
        this.columnNames = columnNames;
        this.customedCtrlArgs = customedCtrlArgs;
        this.autoNumbered = autoNumbered;
        writeCtrlLineArgs();
        enforcer.writeBack();
    }

    /**
     * 在表格缓存的某列中查找匹配给定正则表达式的值，返回所有匹配值所在的记录行
     *
     * @param searchColumnIdx 查找的是第几列，从0开始计数。若要查找的是自动编号列，可设为-1
     * @param targetRegex 查找的值要匹配的正则表达式
     * @return 所有匹配值所在的那行记录
     */
    public String[] select(int searchColumnIdx, String targetRegex)
    {
        if (searchColumnIdx >= columnNames.length || searchColumnIdx < 0)
        {
            if (autoNumbered)
            {
                searchColumnIdx = columnNames.length;
            }
            else
            {
                throw new IndexOutOfBoundsException("搜索列的序号越界了");
            }
        }
        return enforcer.select(searchColumnIdx, targetRegex);
    }

    /**
     * 向表格缓存中插入一行记录
     *
     * @param values 待插入记录的各个值
     * @return 插入是否成功
     */
    public boolean insert(String[] values)
    {
        if (matchedValues(values))
        {
            enforcer.insert(values, autoNumbered);
            return true;
        }
        else
        {
            return false;
        }
    }

    /**
     * 修改若干条缓存记录，将某一列所有匹配给定正则表达式的值所在的行修改为{@code newValue}
     *
     * @param newValues 修改后记录行的所有值
     * @param searchColumnIdx 要匹配的是第几列，从0开始计数。若要查找的是自动编号列，可设为-1
     * @param oldValue 修改前的值要匹配的正则表达式
     * @return 一共修改的行数
     */
    public int update(String[] newValues, int searchColumnIdx, String oldValue)
    {
        if (!matchedValues(newValues))
        {
            return 0;
        }
        if (searchColumnIdx >= columnNames.length || searchColumnIdx < 0)
        {
            if (autoNumbered)
            {
                searchColumnIdx = columnNames.length;
            }
            else
            {
                throw new IndexOutOfBoundsException("搜索列的序号越界了");
            }
        }
        return enforcer.update(newValues, autoNumbered, searchColumnIdx, oldValue);
    }

    /**
     * 将某一列所有匹配给定正则表达式的值所在的行从表格缓存中删除
     *
     * @param searchColumnIdx 要匹配的是第几列，从0开始计数。若要查找的是自动编号列，可设为-1
     * @param targetRegex 删除的值应匹配的正则表达式
     * @return 一共删除的记录行数
     */
    public int delete(int searchColumnIdx, String targetRegex)
    {
        if (searchColumnIdx >= columnNames.length || searchColumnIdx < 0)
        {
            if (autoNumbered)
            {
                searchColumnIdx = columnNames.length;
            }
            else
            {
                throw new IndexOutOfBoundsException("搜索列的序号越界了");
            }
        }
        return enforcer.delete(searchColumnIdx, targetRegex);
    }

    /**
     * 表格缓存是否有自动编号列
     *
     * @return 是否有自动编号列
     */
    public boolean isAutoNumbered()
    {
        return autoNumbered;
    }

    /**
     * 获取表格缓存的各个列名
     *
     * @return 缓存中的各个列名
     */
    public String[] getColumnNames()
    {
        return columnNames;
    }

    /**
     * 重新设置表格缓存的列名，当且仅当新列名的个数与原来的个数相同时
     *
     * @param columnNames 新列名
     * @return 重新设置是否成功
     */
    public boolean setColumnNames(String[] columnNames)
    {
        if (this.columnNames.length == columnNames.length)
        {
            this.columnNames = columnNames;
            return true;
        }
        else
        {
            return false;
        }
    }

    /**
     * 获取表格缓存中的自定义控制参数
     *
     * @return 缓存中的自定义控制参数
     */
    public String[] getCustomedCtrlArgs()
    {
        return customedCtrlArgs;
    }

    /**
     * 重新设置表格缓存中的自定义控制参数
     *
     * @param customedCtrlArgs 新的自定义控制参数
     */
    public void setCustomedCtrlArgs(String[] customedCtrlArgs)
    {
        this.customedCtrlArgs = customedCtrlArgs;
    }

    /**
     * 按真实文件将各控制参数和记录写入缓存中
     *
     * @throws FileNotFoundException 真实文件找不到时抛出
     */
    public void readFile() throws FileNotFoundException
    {
        enforcer.readFile();
        readCtrlLineArgs();
    }

    /**
     * 按缓存完全重写表格的记录文件
     *
     * @throws FileNotFoundException
     * @throws UnsupportedEncodingException
     * @throws IOException
     */
    public void writeBack() throws FileNotFoundException,
            UnsupportedEncodingException, IOException
    {
        writeCtrlLineArgs();
        enforcer.writeBack();
    }
}
